package com.swak.telnet.function;

import org.springframework.util.Assert;

import com.swak.telnet.cmd.Command;

/**
 * 构建 RouterFunction 的入口
 * 
 * @author lifeng
 */
public abstract class RouterFunctions {

	public static RouterFunction cmd(String cmd, HandlerFunction handlerFunction) {
		Assert.notNull(cmd, "'path' must not be null");
		Assert.notNull(handlerFunction, "'handlerFunction' must not be null");
		return new DefaultRouterFunction(RequestPredicates.path(cmd), handlerFunction);
	}

	public static RouterFunction route(RequestPredicate predicate, HandlerFunction handlerFunction) {
		Assert.notNull(predicate, "'predicate' must not be null");
		Assert.notNull(handlerFunction, "'handlerFunction' must not be null");
		return new DefaultRouterFunction(predicate, handlerFunction);
	}

	/**
	 * 实现一些公用的方法
	 * 
	 * @author lifeng
	 */
	private static abstract class AbstractRouterFunction implements RouterFunction {
	}

	/**
	 * 
	 * @author lifeng
	 */
	public static class ComposedRouterFunction extends AbstractRouterFunction {
		private final RouterFunction first;
		private final RouterFunction second;

		ComposedRouterFunction(RouterFunction first, RouterFunction second) {
			this.first = first;
			this.second = second;
		}

		@Override
		public HandlerFunction route(Command request) {
			HandlerFunction hf = first.route(request);
			return hf == null ? second.route(request) : hf;
		}

		/**
		 * 左树
		 * 
		 * @return
		 */
		public RouterFunction getFirst() {
			return first;
		}

		/**
		 * 右树
		 * 
		 * @return
		 */
		public RouterFunction getSecond() {
			return second;
		}

		@Override
		public String toString() {
			return String.format("(left %s or right %s)", first, second);
		}
	}

	/**
	 * 默认的 Router Function
	 * 
	 * @author lifeng
	 */
	public static class DefaultRouterFunction extends AbstractRouterFunction {

		private final RequestPredicate predicate;
		private final HandlerFunction handlerFunction;

		DefaultRouterFunction(RequestPredicate predicate, HandlerFunction handlerFunction) {
			this.predicate = predicate;
			this.handlerFunction = handlerFunction;
		}

		/**
		 * 获得 HandlerFunction
		 */
		@Override
		public HandlerFunction route(Command request) {
			if (this.predicate.test(request)) {
				return this.handlerFunction;
			}
			return null;
		}

		/**
		 * 条件
		 * 
		 * @return
		 */
		public RequestPredicate getPredicate() {
			return predicate;
		}

		@Override
		public String toString() {
			return String.format("(predicate %s -> function %s)", predicate.toString(), handlerFunction.description());
		}
	}
}
